import $ from 'jquery';

import deleteImage from './assets/resourceImage/delete.png';
import rotateImage from './assets/resourceImage/rotate.png';
import reverseImage from './assets/resourceImage/reverse.png';

export function ImageItem(img, x, y, w, h) {
    Object.assign(this, {
        x,
        y,
        w,
        h,
        img,
        opacity: 1,
        active: false,
        selected: false,
        ps: null,
        toolWidth: 24,
        selectable: true,
        scaleMinWidth: 32,
        scaleMinHeight: 32,
        dispose: null,
        overturn: null,
        finishedRotateAngle: 0 //已完成的旋转度数
    });

    let touchRelativeX = 0, touchRelativeY = 0;

    //旋转的中心点
    let rotatePoint = null;
    //操作中的旋转度数
    let rotateAngle = 0;

    //判断是否反向
    this.reverseJudge = 0;

    this.scale = function (s) {
        this.x *= s;
        this.y *= s;
        this.w *= s;
        this.h *= s;
    };

    this.getRotateAngle = function () {
        if (this.disableRotate) {
            return 0;
        }
        return rotateAngle + this.finishedRotateAngle;
    }

    this.draw = function (ctx, drawBolder) {
        //保存canvas全部状态
        ctx.save();
        //图形和图片的透明度
        ctx.globalAlpha = this.opacity;
        //初始坐标
        let zeroX = this.w / 2 + this.x;
        let zeroY = this.h / 2 + this.y;
        ctx.translate(zeroX, zeroY);
        let rAngle = this.getRotateAngle() * Math.PI / 180;
        ctx.rotate(rAngle);
        if (!drawBolder) {
            if (this.reverseJudge % 2 !== 0) {
                ctx.save();
                let x = this.x - zeroX + this.width / 2;
                ctx.translate(x, 0);
                ctx.scale(-1, 1);
                ctx.translate(-x, 0);
                ctx.drawImage(this.img, this.x - zeroX, this.y - zeroY, this.w, this.h);
                ctx.restore();
            } else {
                this.drawBg && this.drawBg(ctx, this.x - zeroX, this.y - zeroY);
                ctx.drawImage(this.img, -this.w / 2, -this.h / 2, this.w, this.h);
                this.drawFg && this.drawFg(ctx, -this.w / 2, -this.h / 2);
            }

        }

        if (this.selected && drawBolder) {
            ctx.setLineDash([5, 7]);
            ctx.strokeStyle = '#ff7237';
            ctx.beginPath();
            ctx.rect(-this.w / 2, -this.h / 2, this.w, this.h);
            ctx.stroke();
            ctx.closePath();
            this.drawCustomTool && this.drawCustomTool(ctx, zeroX, zeroY);
        }

        ctx.restore();
    }

    //判断触摸点是否在旋转图标上
    this.isInRotateTool = function (x, y) {
        return x > this.x + this.w - this.toolWidth / 2 && y > this.y + this.h - this.toolWidth / 2;
    }

    this.transformPosition = function (x, y) {
        const centerX = this.x + this.w / 2;
        const centerY = this.y + this.h / 2;
        let angle = -this.finishedRotateAngle;
        angle = angle < 0 ? 360 + angle : angle;
        angle = angle / 180 * Math.PI; //求出对应的弧度
        //坐标旋转公式
        const actualX = (x - centerX) * Math.cos(angle) - (y - centerY) * Math.sin(angle) + centerX;
        const actualY = (y - centerY) * Math.cos(angle) + (x - centerX) * Math.sin(angle) + centerY;
        return {
            x: actualX,
            y: actualY
        }
    }

    this.zoom = function (scale) {
        const append = scale - 1;
        const targetW = this.w + append * this.w;
        if (scale < 1 && targetW < this.scaleMinWidth) {
            return;
        }
        const targetH = this.h + append * this.h;
        if (scale < 1 && targetH < this.scaleMinHeight) {
            return;
        }
        this.x = this.x - append * this.w / 2;
        this.y = this.y - append * this.h / 2;
        this.w = targetW;
        this.h = targetH;
    }

    this.touchStart = function (ex, ey) {
        touchRelativeX = ex - this.x;
        touchRelativeY = ey - this.y;
        this.active = true;
        this.opacity = 0.4;
        const p = this.transformPosition(ex, ey);
        if (this.isInRotateTool(p.x, p.y)) {
            rotatePoint = {
                w: this.w,
                h: this.h,
                x: this.x + this.w / 2,
                y: this.y + this.h / 2,
                angle: this.finishedRotateAngle
            };
            rotatePoint.distance = Math.sqrt(Math.pow((touchRelativeX - this.w / 2), 2) + Math.pow(touchRelativeY - this.h / 2, 2));
            if (isNaN(rotatePoint.distance)) {
                rotatePoint = null;
            }
        } else {
            rotatePoint = null;
        }
    };
    this.touchMove = function (ex, ey) {
        if (rotatePoint && this.rotateScale) {
            //获取旋转角度
            rotateAngle = (180 / Math.PI * Math.atan(((rotatePoint.y - ey) / (rotatePoint.x - ex)))) -
                180 / Math.PI * Math.atan(this.h / this.w) - rotatePoint.angle;
            if (rotatePoint.x > ex) {
                rotateAngle += 180;
            }
            rotateAngle %= 360;
            const newDistance = Math.sqrt(Math.pow(ex - this.x - this.w / 2, 2) + Math.pow(ey - this.y - this.h / 2, 2));
            if (isNaN(newDistance)) {
                return;
            }
            const scaleRate = newDistance / rotatePoint.distance;
            this.zoom(rotatePoint.w * scaleRate / this.w);
        } else if (this.dragable) {
            this.x = ex - touchRelativeX;
            this.y = ey - touchRelativeY;
        }
    }
    this.touchEnd = function (ex, ey) {
        if (rotatePoint) {
            rotatePoint = null;
            this.finishedRotateAngle = this.getRotateAngle();
            this.finishedRotateAngle %= 360;
            rotateAngle = 0;
        }
        this.opacity = 1;
    }

    this.select = function (ex, ey) {
        const p = this.transformPosition(ex, ey);
        if (!this.selected) {
            this.selected = true;
            return true;
        } else if (this.fireCustomTool && this.fireCustomTool(p.x, p.y)) {
            //调用每个类型单独的判断
            return true;
        } else {
            this.unSelect();
            return false;
        }
    }

    this.unSelect = function () {
        this.selected = false;
    }

    this.inMyControl = function (x, y) {
        const p = this.transformPosition(x, y);
        const bigger = this.selected ? this.toolWidth / 2 : 0;
        return p.x >= this.x - bigger && p.x <= this.x + this.w + bigger && p.y >= this.y - bigger && p.y <= this.y + this.h + bigger;
    }

}

export function BackgroundItem(img, x, y, w, h) {
    //禁用工具
    this.disableTool = true;
    //禁止拖动
    this.dragable = false;
    //禁止旋转
    this.disableRotate = true;
    this.clearOpacity = 1;

    ImageItem.call(this, img, x, y, w, h);
    this.selectable = false;
    this.disableFg = false;
    this.disableBg = false;
    this.itemName = "background";
    this.drawCustomTool = function (ctx, zeroX, zeroY) {
        if (this.ps.resource.rotateImg) {
            ctx.drawImage(this.ps.resource.rotateImg, this.x + this.w - this.toolWidth - zeroX, this.y + this.h - this.toolWidth - zeroY, this.toolWidth, this.toolWidth);
        }
    }
    const superAngle = this.getRotateAngle();
    this.getRotateAngle = function () {
        if (this.disableRotate) {
            return 0;
        }
        let angle = superAngle.call(this);
        let temp = window.parseInt(angle / 45);
        if (temp % 2 === 1) {
            temp++;
        } else if (temp % 2 === -1) {
            temp--;
        }
        angle = temp * 45;
        return angle;
    }
    this.isInRotateTool = function (x, y) {
        return x > this.x + this.w - this.toolWidth && y > this.y + this.h - this.toolWidth;
    }

    this.whenSelectedItem = function (item) {

    }

    const superDraw = this.draw;
    this.draw = function (ctx) {
        // ctx.save();
        // ctx.fillStyle = "black";
        // ctx.globalAlpha = 0.05;
        // ctx.fillRect(0, 0, this.ps.getW(), this.ps.getH());
        superDraw.call(this, ctx);
        // ctx.restore();
    }

    this.clearOutArea = function (ctx) {
        ctx.save();
        ctx.fillStyle = "#FFFFFF";
        ctx.globalAlpha = this.clearOpacity;
        ctx.restore();
        ctx.save();
    }

    this.drawBg = function (ctx, x, y) {
        if (this.disableBg) {
            return;
        }
        ctx.save();
        ctx.fillStyle = "#ffffff";
        ctx.globalAlpha = 0.3;
        ctx.fill();
        ctx.restore();
    }

    this.drawFg = function (ctx, x, y) {
        // if (this.disableFg) {
        //     return;
        // }
        // ctx.setLineDash([1, 1]);
        // ctx.strokeStyle = "#666666";
        // ctx.beginPath();
        // ctx.rect(x, y, this.w, this.h);
        // ctx.stroke();
        // ctx.closePath();
    }

}

export function IconItem(img, x, y, w, h) {
    ImageItem.call(this, img, x, y, w, h);
    this.rotateScale = true;
    this.dragable = true;
    this.itemName = "icon";
    this.drawCustomTool = function (ctx, zeroX, zeroY) {
        if (this.ps.resource.deleteImg) {
            ctx.drawImage(this.ps.resource.deleteImg, this.x - this.toolWidth / 2 - zeroX + this.w, this.y - this.toolWidth / 2 - zeroY, this.toolWidth, this.toolWidth);
        }
        if (this.ps.resource.rotateImg) {
            ctx.drawImage(this.ps.resource.rotateImg, this.x + this.w - this.toolWidth / 2 - zeroX, this.y + this.h - this.toolWidth / 2 - zeroY, this.toolWidth, this.toolWidth);
        }
        if (this.ps.resource.reverseImg) {
            ctx.drawImage(this.ps.resource.reverseImg, this.x - this.toolWidth / 2 - zeroX, this.y - this.toolWidth / 2 - zeroY, this.toolWidth, this.toolWidth);
        }
    }
    this.fireCustomTool = function (x, y) {
        if (x > this.toolWidth / 2 + this.x && x < this.toolWidth / 2 + this.x + this.w && y < this.toolWidth / 2 + this.y) {
            this.dispose();
            return true;
        } else if (x < this.toolWidth / 2 + this.x && y < this.toolWidth / 2 + this.y) {
            this.overturn();
            return true
        } else {
            return false;
        }
    }
}

export function TextItem(img, x, y, w, h) {
    this.disableRotate = false;
    IconItem.call(this, img, x, y, w, h);
    this.rotateScale = true;
    this.dragable = true;
    this.itemName = "text";
}

export function MaskItem(w, h, imgData) {
    this.imgElem = document.createElement("img");
    this.imgElem.src = imgData;
    this.x = 0;
    this.y = 0;
    this.w = w;
    this.h = h;
    this.draw = function (ctx) {
        ctx.drawImage(this.imgElem, 0, 0, this.w, this.h);
    }
    this.scale = function (s) {
        this.x *= s;
        this.y *= s;
        this.w *= s;
        this.h *= s;
    }
}

export function PS(cvs) {
    const canvas = cvs;
    let ctx = canvas.getContext('2d');
    let W = $(canvas).width(); //画布的css宽度
    let H = $(canvas).height(); //画布的css高度
    const canvasWScale = canvas.width / W; //画布的宽度缩放比例
    const canvasHScale = canvas.height / H; //画布的高度缩放比例
    ctx.scale(canvasWScale, canvasHScale);
    this.models = [];
    let backgroundItem = null;
    let _ = this;
    let cx = $(canvas).offset().left; //画布的横坐标
    let cy = $(canvas).offset().top; //画布的纵坐标
    this.resource = {};
    let selectedItem = null;
    let mask = null;

    this.updateCanvasLocation = function () {
        cy = $(canvas).offset().top;
    }

    this.scale = function (s) {
        canvas.height = s * H;
        canvas.width = s * W;
        for (let i in _.models) {
            const m = _.models[i];
            m.scale(s);
            m.unSelect();
        }
        if (backgroundItem) {
            backgroundItem.scale(s);
            backgroundItem.unSelect();
        }
        mask.scale(s);
        W *= s;
        H *= s;
    }

    this.selectedItem = function () {
        return selectedItem;
    }

    this.createMask = function (maskData) {
        mask = new MaskItem(W, H, maskData);
    }

    this.getH = function () {
        return H;
    }

    this.getW = function () {
        return W;
    }

    this.removeBackground = function () {
        backgroundItem = null;
    }

    this.removeModel = function (model) {
        this.clear();
        for (const i in _.models) {
            if (_.models[i] === model) {
                _.models.splice(i, 1);
                break;
            }
        }
        _.render();
    }

    this.reverseModel = function (model) {
        this.clear();
        for (const i in _.models) {
            if (_.models[i] === model) {
                _.models[i].reverseJudge++;
                break;
            }
        }
        _.render();
    }

    this.addModel = function (model) {
        _.models.push(model);
        model.dispose = function () {
            _.removeModel(model);
        }
        model.overturn = function () {
            _.reverseModel(model);
        }
        model.ps = this;
    }

    this.setBackground = function (bgItem) {
        backgroundItem = bgItem;
        bgItem.ps = this;
    }

    this.modelsUnSelect = function () {
        this.clear();
        let models = _.models;
        if (backgroundItem != null) {
            backgroundItem.draw(ctx);
        }
        for (const i in models) {
            models[i].selected = false;
            models[i].draw(ctx);
        }
        if (backgroundItem != null) {
            backgroundItem.clearOutArea(ctx, 0.9);
        }
        for (const i in models) {
            models[i].draw(ctx, true);
        }
        // mask.draw(ctx);
        selectedItem && selectedItem.draw(ctx, true);
    }

    this.clear = function () {
        ctx.rect(0, 0, W, H);
        ctx.fillStyle = "white";
        ctx.fillRect(0, 0, W, H);
        ctx.rotate(0);
    }

    this.render = function () {
        this.clear();
        if (backgroundItem != null) {
            backgroundItem.draw(ctx);
        }
        for (const i in _.models) {
            _.models[i].draw(ctx);
        }
        if (backgroundItem != null) {
            backgroundItem.clearOutArea(ctx, 0.9);
        }
        for (const i in _.models) {
            _.models[i].draw(ctx, true);
        }
        // mask.draw(ctx);
        selectedItem && selectedItem.draw(ctx, true);
    }

    this.save = function (px) {
        const s = px / H;
        this.scale(s);
        backgroundItem.disableBg = false;
        backgroundItem.disableFg = false;
        this.render();
        const base64 = canvas.toDataURL('image/png');
        this.scale(1 / s);
        backgroundItem.disableFg = false;
        backgroundItem.disableBg = false;
        this.render();
        return base64;
    }

    initResource();

    bindEvent();

    //初始化资源，添加删除图片和旋转放大图片
    function initResource() {
        let del = new Image();
        del.src = deleteImage;
        del.onload = function () {
            _.resource.deleteImg = del;
        };
        let rotate = new Image();
        rotate.src = rotateImage;
        rotate.onload = function () {
            _.resource.rotateImg = rotate;
        }
        let reverse = new Image();
        reverse.src = reverseImage;
        reverse.onload = function () {
            _.resource.reverseImg = reverse;
        }
    }

    //初始化事件
    function bindEvent() {
        let touchingItem = null;
        let zoomInitDistance = 0;
        let startMovingTime = 0;

        function dispatchEvent(ex, ey, whenIn) {
            //图片在画布中横坐标
            let x = ex - cy;
            //图片在画布中纵坐标
            let y = ey - cy;
            for (let i = _.models.length - 1; i >= 0; i--) {
                if (_.models[i].inMyControl(x, y)) {
                    const cur = _.models[i];
                    _.models.splice(i, 1);
                    _.models.push(cur);
                    whenIn(cur, x, y);
                    return;
                }
            }
            if (backgroundItem && backgroundItem.inMyControl(x, y)) {
                whenIn(backgroundItem, x, y);
            }
            // if (selectedItem) {
            //     selectedItem.unSelect();
            //     _.render();
            // }

        }

        function whenClick(e, isPC) {
            let effect = false;
            dispatchEvent(isPC ? e.clientX : e.changedTouches[0].clientX, isPC ? e.clientY : e.changedTouches[0].clientY, function (item, x, y) {
                effect = _.clickItem(item, x, y);
            });
            return effect;
        }

        _.clickItem = function (item, x, y) {
            if (selectedItem && !selectedItem.selected) {
                selectedItem = null;
            }
            if (!item.selectable) {
                return;
            }
            const preSelected = selectedItem;
            selectedItem = item;

            const selected = selectedItem.select(x, y);
            // _.whenSelectedItem(selected?selectedItem:null);

            if (preSelected && selectedItem !== preSelected) {
                preSelected.unSelect();
            }
            _.render();
            return true;
        };

        canvas.addEventListener("touchstart", function (e) {
            if (selectedItem && !selectedItem.selected) {
                selectedItem = null;
            }

            const touches = e.touches;
            if (touches.length === 1) {
                dispatchEvent(touches[0].clientX, touches[0].clientY, function (item, x, y) {
                    // if (selectedItem === null) {
                    //     return;
                    // }
                    if (item.drawBg) {
                        return;
                    }
                    touchingItem = item;
                    touchingItem.touchStart(x, y);
                    e.preventDefault();
                });
                startMovingTime = new Date().getTime();
            } else if (touches.length === 2 && selectedItem) {
                const dx = touches[0].clientX - touches[1].clientX;
                const dy = touches[0].clientY - touches[1].clientY;
                zoomInitDistance = Math.sqrt(dx * dx + dy * dy);
                e.preventDefault();
            }
        });

        canvas.addEventListener("touchmove", function (e) {
            const touches = e.touches;
            if (touches.length === 1) {
                if (!touchingItem) {
                    return;
                }
                const touch = e.touches[0];
                const x = touch.clientX - cx;
                const y = touch.clientY - cy;
                touchingItem.touchMove(x, y);
            } else if (touches.length === 2 && selectedItem) {
                const dx = touches[0].clientX - touches[1].clientX;
                const dy = touches[0].clientY - touches[1].clientY;
                const newDistance = Math.sqrt(dx * dx + dy * dy);
                selectedItem.zoom(newDistance / zoomInitDistance);
                zoomInitDistance = newDistance;
            }
            e.preventDefault();
            _.render();
        });

        canvas.addEventListener("touchend", function (e) {
            end(e, false);
        });

        canvas.addEventListener('mousedown', function (e) {
            if (selectedItem && !selectedItem.selected) {
                selectedItem = null;
            }
            dispatchEvent(e.clientX, e.clientY, function (item, x, y) {
                // if (selectedItem === null) {
                //     return;
                // }
                if (item.drawBg) {
                    return;
                }
                touchingItem = item;
                touchingItem.touchStart(x, y);
                e.preventDefault();
            });
            startMovingTime = new Date().getTime();
        });
        canvas.addEventListener("mousemove", function (e) {
            if (!touchingItem) {
                return;
            }
            const x = e.clientX - cx;
            const y = e.clientY - cy;
            touchingItem.touchMove(x, y);
            e.preventDefault();
            _.render();
        });

        canvas.addEventListener("mouseup", function (e) {
            end(e, true);
        });

        function end(e, isPC) {
            if (!touchingItem) {
                if (new Date().getTime() - startMovingTime < 200) {
                    selectedItem && selectedItem.unSelect();
                    // _.whenSelectedItem(null)
                    _.render();
                }
                return;
            }
            touchingItem.touchEnd();
            let rendered = false;
            if (new Date().getTime() - startMovingTime < 200) {
                rendered = whenClick(e, isPC);
            }
            touchingItem = null;
            if (!rendered) {
                _.render();
            }
        }

    }

}